home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / kernel / rs232.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  21KB  |  715 lines

  1. #include "kernel.h"
  2. #include <signal.h>
  3. #include <minix/callnr.h>
  4. #include <minix/com.h>
  5. #include <sgtty.h>
  6. #include "proc.h"
  7. #include "tty.h"
  8. #if (CHIP == M68000)
  9. #include "staddr.h"
  10. #include "stmfp.h"
  11. #endif
  12.  
  13. /* Definitions used by the RS232 driver. */
  14. #define    RS_BUF_SIZE         256    /* output buffer per serial line */
  15. #define SPARE                     16    /* leave room in buffer for echoes */
  16. #define THRESHOLD                 20    /* # chars to accumulate before msg */
  17.  
  18. #if (CHIP != M68000)
  19. #define PRIMARY                0x3F8    /* I/O port of primary RS232 */
  20. #define SECONDARY              0x2F8    /* I/O port of secondary RS232 */
  21.  
  22. /* Constants relating to the 8250. */
  23. #define    RS232_RATE_DIVISOR       0    /* address of baud rate divisor reg */
  24. #define    RS232_TRANSMIT_HOLDING       0    /* address of transmitter holding reg*/
  25. #define    RS232_RECEIVER_DATA_REG       0    /* address of receiver data register */
  26. #define    RS232_INTERRUPTS       1    /* address of interrupt enable reg */
  27. #define    RS232_INTERRUPT_ID_REG       2    /* address of interrupt id register */
  28. #define    RS232_LINE_CONTROL       3    /* address of line control register */
  29. #define    RS232_MODEM_CONTROL       4    /* address of modem control register */
  30. #define    RS232_LINE_STATUS       5    /* address of line status register */
  31. #define    RS232_MODEM_STATUS       6    /* address of modem status register */
  32. #define    LINE_CONTROLS        0x0B    /* odd parity,1 stop bit,8 data bits */
  33. #define    MODEM_CONTROLS        0x0B    /* RTS & DTR */
  34. #define    ADDRESS_DIVISOR        0x80    /* value to address divisor */
  35. #define HOLDING_REG_EMPTY       0x20    /* transmitter holding reg empty */
  36. #define    RS232_INTERRUPT_CLASSES    0x03    /* receiver Data Ready & xmt empty */
  37. #define    UART_FREQ           115200L    /* UART timer frequency */
  38. #endif
  39.  
  40. #define DEF_BAUD                1200    /* default baud rate */
  41.  
  42. /* Line control setting related constants. */
  43. #define ODD               0
  44. #define    EVEN               1
  45. #define NONE              -1
  46. #define    PARITY_TYPE_SHIFT       4    /* shift count for parity_type bit */
  47. #define    STOP_BITS_SHIFT           2    /* shift count for # stop_bits */
  48. #define DATA_LEN                   8    /* how much to shift sg_mode for len */
  49.  
  50. #if (CHIP != M68000)
  51. #define    PARITY_ON_OFF        0x08    /* position of parity bit in line reg*/
  52.  
  53. /* RS232 interrupt types. */
  54. #define MODEM_STATUS            0x00    /* UART modem status change */
  55. #define TRANSMITTER_READY    0x02    /* transmitter ready to accept data */
  56. #define RECEIVER_READY        0x04    /* data received interrupt */
  57. #define LINE_STATUS             0x06    /* UART line status change */
  58. #define INT_TYPE_MASK        0x06    /* mask to mask out interrupt type */
  59. #define    INT_PENDING        0x01    /* position of interrupt-pending bit */
  60.  
  61. /* Status register values. */
  62. #define DATA_REGISTER_EMPTY    0x20    /* mask to see if data reg is empty */
  63. #define DATA_RECEIVED        0x01    /* mask to see if data has arrived */
  64. #endif
  65.  
  66. #if (CHIP == M68000)
  67. #define SIAIN(c)    (c) = MFP->mf_udr
  68. #define SIAOUT(c)    {lastchar = (c); MFP->mf_udr = lastchar;}
  69. #endif
  70.  
  71. /* Global variables used by the RS232 driver. */
  72. #if (CHIP != M68000)
  73. PRIVATE int first_rs_write_int_seen = FALSE;
  74. #endif
  75.  
  76. PRIVATE struct rs_struct{
  77.   int rs_base;            /* 0x3F8 for primary, 0x2F8 secondary*/
  78.                 /* unused on ST */
  79.   int rs_busy;            /* line is idle or not */
  80.   int rs_left;            /* # chars left in buffer to output */
  81.   char *rs_next;        /* pointer to next char to output */
  82.   char rs_buf[RS_BUF_SIZE];    /* output buffer */
  83. } rs_struct[NR_RS_LINES];
  84.  
  85. #if (CHIP == M68000)
  86.  
  87. PRIVATE int dummy;    /* to read error chars in */
  88. PRIVATE int lastchar;    /* save last outputted char for retry */
  89.  
  90. PUBLIC  void rs_flush();
  91. PUBLIC  void rs_out_char();
  92. PUBLIC  void rs_sig();
  93. PUBLIC  void init_rs232();
  94. PUBLIC  void set_uart();
  95. PRIVATE    void rs_read_int();
  96. PRIVATE    void rs_write_int();
  97. PRIVATE void rs_feed();
  98. PRIVATE    void start_rs232();
  99. PRIVATE    void serial_out();
  100. PRIVATE void rs_expand();
  101. PRIVATE    void config_rs232();
  102.  
  103. PUBLIC void
  104. siaint(type)
  105. int    type;           /* interrupt type */
  106. {
  107.     register unsigned char  code;
  108.     register struct tty_struct    *tp;
  109.     int s = lock();
  110.  
  111.     switch (type & 0x00FF)
  112.     {
  113.         case 0x00:           /* receive buffer full */
  114.             rs_read_int(SERIAL1);
  115.             break;
  116.         case 0x01:           /* receive error */
  117.             printf("sia: receive error: status=%x\r\n", MFP->mf_rsr);
  118.             MFP->mf_rsr &= R_ENA;
  119.             SIAIN(dummy); /* discard char in case of overrun */
  120.             break;
  121.         case 0x02:           /* transmit buffer empty */
  122.             rs_write_int(SERIAL1);
  123.             break;
  124.         case 0x03:           /* transmit error */
  125.             code = MFP->mf_tsr;
  126.             if (code & ~(T_ENA | T_UE | T_EMPTY))
  127.             {
  128.                 printf("sia: transmit error: status=%x\r\n", code);
  129.                 SIAOUT(lastchar);    /* retry */
  130.             }
  131.             break;
  132.     }
  133.     restore(s);
  134. }
  135.  
  136. #else
  137. /*===========================================================================*
  138.  *                rs232                          *
  139.  *===========================================================================*/
  140. PUBLIC void rs232(unit)
  141. int unit;                /* which unit caused the interrupt */
  142. {
  143. /* When an RS232 interrupt occurs, mpx88.s catches it and calls rs232().
  144.  * Because more than one interrupt condition can occur at the same
  145.  * time, the conditions are presented in the interrupt-identification
  146.  * register in priority order, we have to keep scanning until the 
  147.  * interrupt-pending bit goes down.  Only one communications port is really
  148.  * supported here because the other vector is used by the Ethernet.
  149.  */
  150.  
  151.   int interrupt_type, t, old_state, val;
  152.   struct rs_struct *rs;
  153.  
  154.   old_state = lock();
  155.   rs = &rs_struct[unit - NR_CONS];
  156.   while (TRUE) {
  157.     port_in(rs->rs_base + RS232_INTERRUPT_ID_REG, &interrupt_type); 
  158.     if ((interrupt_type & INT_PENDING) == 1) break;    /* 1 = no interrupt */
  159.     t = interrupt_type & INT_TYPE_MASK;
  160.     switch(t) {
  161.         case RECEIVER_READY:    /* a character has arrived */
  162.         rs_read_int(unit);
  163.         break;
  164.  
  165.         case TRANSMITTER_READY:    /* a character has been output */
  166.         rs_write_int(unit);
  167.         break;
  168.  
  169.         case LINE_STATUS:        /* line status event, (disabled) */
  170.         port_in(rs_struct[unit-1].rs_base + RS232_LINE_STATUS, &val);
  171.         printf("RS 232 line status event %x\n", val);
  172.         break;
  173.  
  174.         case MODEM_STATUS:        /* modem status event, (disabled) */
  175.         port_in(rs_struct[unit-1].rs_base + RS232_MODEM_STATUS, &val);
  176.         printf("RS 232 modem status event %x\n", val);
  177.         break;
  178.     }
  179.   }
  180.   restore(old_state);
  181. }
  182. #endif
  183.  
  184.  
  185. /*===========================================================================*
  186.  *                rs_read_int                      *
  187.  *===========================================================================*/
  188. PRIVATE    void rs_read_int(line)
  189. int line;
  190. {
  191.   int val, k, base;
  192.  
  193.   base = rs_struct[line - NR_CONS].rs_base;
  194.  
  195.   /* Fetch the character from the RS232 hardware. */
  196. #if (CHIP == M68000)
  197.   SIAIN(val);
  198. #else
  199.   port_in(base + RS232_RECEIVER_DATA_REG, &val);
  200. #endif
  201.  
  202.   /* Store the character in memory so the task can get at it later */
  203.   if ((k = tty_buf_count(tty_driver_buf)) < tty_buf_max(tty_driver_buf)) {
  204.     /* There is room to store this character, do it */
  205.     k = k + k;            /* each entry contains two bytes */
  206.     tty_driver_buf[k + 4] = val;    /* store the ascii code */
  207.     tty_driver_buf[k + 5] = line;    /* tell wich line it came from */ 
  208.     tty_buf_count(tty_driver_buf)++;        /* increment counter */
  209.  
  210.     if (tty_buf_count(tty_driver_buf) < THRESHOLD) {
  211.         /* Don't send message.  Just accumulate.  Let clock do it. */
  212.         INT_CTL_ENABLE;
  213.         flush_flag++;
  214.         return;
  215.     }
  216.     rs_flush();            /* send TTY task a message */
  217.   } else {
  218.     /* Too many character have been buffered. Discard excess */
  219.     INT_CTL_ENABLE;
  220.   }
  221. }
  222.  
  223.  
  224. /*===========================================================================*
  225.  *                rs_flush                        *
  226.  *===========================================================================*/
  227. PUBLIC void rs_flush()
  228. {
  229. /* Flush the tty_driver_buf by sending a message to TTY.  This procedure can
  230.  * be triggered locally, when a character arrives, or by the clock task.
  231.  */
  232.   int s = lock();
  233.  
  234.   /* Build and send the interrupt message */ 
  235.   flush_flag = 0;
  236.   if ((tty_buf_count(tty_driver_buf) == 0) && (output_done == 0)) return;    /* nothing to flush */
  237.   interrupt(TTY);    /* send a message to the tty task */
  238.   restore(s);
  239. }
  240.  
  241.  
  242. /*===========================================================================*
  243.  *                rs_write_int                        *
  244.  *===========================================================================*/
  245. PRI